home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / SAT / SAT Invaders sample ƒ / main.p < prev    next >
Encoding:
Text File  |  1994-07-26  |  9.9 KB  |  324 lines  |  [TEXT/PJMM]

  1. {================================================}
  2. {=============== SATInvaders main unit ================}
  3. {================================================}
  4.  
  5. { Example file for Ingemars Sprite Animation Toolkit. }
  6. { © Ingemar Ragnemalm 1992 }
  7. { See doc files for legal terms for using this code. }
  8.  
  9. { SATInvaders is a very simple game demonstrating how to use the Sprite Animation}
  10. { Toolkit. It is intended as a minimal demonstration, without many features and options}
  11. { that the other sample program, HeartQuest, has. No high scores or even score, only}
  12. { one life, doesn't save settings, only one kind of enemy, no special effects like explosions}
  13. { etc. However, it is still a full Mac application with menus and event handling (using}
  14. {TransSkel). There are now some even more "minimal" demos without that.}
  15.  
  16. program SATInvaders;
  17.  
  18.     uses
  19.         TransSkel, SAT, GameGlobals, SoundConst, sPlayer, sEnemy, sShot, sMissile;
  20.  
  21.     var
  22.         soundFlag, plotFastFlag: Boolean;
  23.  
  24. { -------------------------------------------------------------------- }
  25. {                                Game driver procedures                                }
  26. { -------------------------------------------------------------------- }
  27.  
  28. { Setup a new level. This is called when the game starts and at each new level.}
  29.     procedure SetupLevel (level: integer);
  30.         var
  31.             i, j: integer;
  32.             sp: SpritePtr;
  33.     begin { SetupLevel }
  34.  
  35. { Clear the Sprite list! Note that this leaves the images "dead" on the screen,}
  36. { but we will soon erase them. }
  37.         while gSAT.sRoot <> nil do
  38.             KillSprite(gSAT.sRoot);
  39.  
  40.         missileCount := 0; { count variable in mMissile }
  41.  
  42. { Create all the enemy sprites for the level, depending on the level number. }
  43.         for i := 0 to (level + 1) do
  44.             for j := 0 to (level div 2) + 1 do
  45.                 sp := NewSprite(-3, i * 40 + 2, j * 40 - 40 * (level div 2 + 1), @SetupEnemy);
  46.  
  47. { Make the player sprite. }
  48.         sp := NewSprite(2, gSAT.offSizeH div 2, gSAT.offSizeV - 40, @SetupPlayer);
  49.  
  50. { Copy BackScreen to OffScreen to erase old sprites. }
  51.         CopyBits(gSAT.backScreen^.portbits, gSAT.offScreen^.portbits, gSAT.offScreen^.portrect, gSAT.offScreen^.portrect, srcCopy, nil);
  52.         PeekOffScreen;
  53.     end; { SetupLevel }
  54.  
  55. { Start a new game. Initialize level, score, number of lives, and call setuplevel to make the first level. }
  56.     procedure StartGame;
  57.     begin
  58.         Level := 1;
  59.         SetupLevel(level);
  60.     end;
  61.  
  62. { Declare forward since we want to call it from MoveIt }
  63.     procedure DoFileMenu (item: integer);
  64.     forward;
  65.  
  66. { This routine is the game driver. It calls RunSAT repeatedly until the game ends or is paused. }
  67. { I also read the keyboard here. This could optionally be moved to the "player object" module. }
  68.  
  69.     procedure MoveIt;
  70.         var
  71.             t: longint;
  72.             theEvent: EventRecord; { för att testa musklick }
  73.     begin
  74.         stillrunning := true; { A flag that tells whether or not to quit this routine. }
  75.  
  76. { Hide cursor and menu bar }
  77.  { NOTE: No matter how we leave the MoveIt procedure, we should ShowCursor. }
  78.         HideCursor;
  79.         HideMBar(gSAT.wind);
  80.         PeekOffscreen; {We must redraw the menu bar area. I'm lazy and redraw it all.}
  81.  
  82. { Main loop! Keep running until the game is paused or ends. }
  83.         while stillrunning = true do
  84.             begin
  85.                 t := TickCount; {Remember when we started the last turn through the loop.}
  86.  
  87. { Here is the real heart of the loop: call Animator once per loop. It will call all the objects,}
  88. { draw and erase them, sort them etc. }
  89.                 RunSAT(plotFastFlag);
  90.  
  91. { All the rest of the main loop is game specific, next level, bonus handling, etc. }
  92.  
  93. {Handle the speed of the invaders. Since all move the same way, this is done globally.}
  94.                 if globalspeed.h = 0 then
  95.                     begin
  96.                         downcount := pred(downcount);
  97.                         if downcount <= 0 then
  98.                             begin
  99.                                 globalspeed.h := -lasth;
  100.                                 globalspeed.v := 0;
  101.                                 turnflag := false;
  102.                             end;
  103.                     end
  104.                 else if turnflag then
  105.                     begin
  106.                         downcount := 10;
  107.                         lasth := globalspeed.h;
  108.                         globalspeed.h := 0;
  109.                         globalspeed.v := 3;
  110.                     end;
  111.  
  112. {End of level? If so, set up a new one!}
  113.                 if not gSAT.anyMonsters then
  114.                     begin
  115.                         SATSoundShutUp;
  116.                         level := level + 1;
  117.                         SetupLevel(level);
  118.                     end; {if not anymonsters}
  119.  
  120. { Check for keys being pressed - but don't allow background processing.}
  121. { If you want background processing, either use GetNextEvent+SystemTask or WaitNextEvent (the modern call).}
  122.                 if GetOSEvent(keyDownMask, theEvent) then { keydown only }
  123.                     if BitAnd(theEvent.modifiers, cmdKey) <> 0 then {Command key pressed?}
  124.                         case char(BitAnd(theEvent.message, charCodeMask)) of {With what key?}
  125.                             'q': 
  126.                                 begin {Quit!}
  127.                                     SkelWhoa;        {Tell TransSkel to quit.}
  128. { Do all the things we have to do when we leave MoveIt! }
  129.                                     SATSoundShutUp; { Dispose of sound channel }
  130.                                     FlushEvents(EveryEvent, 0); { To forget events, like mouse clicks etc. }
  131.                                     ShowCursor;
  132.                                     ShowMBar;
  133.                                     exit(MoveIt);
  134.                                 end;
  135.                             's': 
  136.                                 begin {Sound on/off}
  137.                                     DoFileMenu(sound);
  138.                                 end;
  139.                             otherwise
  140.                                 ; {Ignore others}
  141.                         end; { case}
  142.  
  143. { Delay, using TickCount so it doesn't matter how fast our Mac is. }
  144.                 while ((TickCount - t) < 3) do {3/60 per frame = 20 fps if possible}
  145.                     ;
  146.             end; { while stillrunning (main loop) }
  147.  
  148.         while not SATSoundDone do
  149.             SATSoundEvents; {Wait for last sound to complete}
  150.  
  151.         ShowCursor; {Balance HideCursor}
  152.         ShowMBar;
  153.         FlushEvents(EveryEvent - DiskMask, 0); { To forget events, like mouse clicks etc. except disk events }
  154.  
  155.         ReportStr('Sorry, game over.');
  156.  
  157.         SATSoundShutUp; { Dispose of sound channel }
  158.     end; { MoveIt }
  159.  
  160.     procedure GameWindUpdate;
  161.         var
  162.             watch: CursHandle;
  163.     begin
  164. {Set the cursor to wait cursor during screen depth change test. If there's no change,}
  165. {the user won't notice.}
  166.         watch := GetCursor(WatchCursor);
  167.         SetCursor(watch^^);
  168.         if SATDepthChangeTest then
  169.             begin
  170. {Do anything needed after a screen depth change. In this demo, nothing.}
  171.             end;
  172.         ReleaseResource(Handle(watch));
  173. {Set the cursor to arrow again.}
  174.         InitCursor;
  175.  
  176. {Process the update event by redrawing the window.}
  177.         PeekOffScreen;
  178.  
  179. {Note: PeekOffScreen can be replaced by drawing with CopyBits, i.e.:}
  180. {SATSetPortScreen;}
  181. {CopyBits(offScreen^.portBits, SATwind^.portBits, offScreen^.portRect, offScreen^.portRect, srcCopy, nil);}
  182. {plus drawing borders. PeekOffScreen draws them black.}
  183.     end;
  184.  
  185. {    Process selection from File menu.}
  186.  
  187.     procedure DoFileMenu (item: integer);
  188.     begin
  189.         case item of
  190.             run: 
  191.                 begin
  192. { Test if we have Color QD, and if so, test bit depth! Alert if features^^.PlotFast.}
  193.                     if not ((gSAT.initDepth = 1) or (gSAT.initDepth = 4) or (gSAT.initDepth = 8)) and plotFastFlag then
  194.                         begin
  195.                             ReportStr('Please uncheck ''Fast animation'' or set the monitor to b/w, 4-bit or 8-bit mode in the Control Panel.');
  196.                             exit(DoFileMenu);
  197.                         end;
  198.                     if SATDepthChangeTest then {Update if necessary}
  199.                         ;
  200.                     StartGame;
  201.                     ShowWindow(gSAT.wind);
  202.                     SelectWindow(gSAT.wind);
  203.                     GameWindUpdate;
  204.                     MoveIt;
  205.                 end;
  206.             sound: 
  207.                 begin
  208.                     soundFlag := not soundFlag;
  209.                     CheckItem(FileMenu, sound, soundFlag);
  210.                     if soundFlag then { Tell the sound package our settings, so we don't have to bother. }
  211.                         SATSoundOn
  212.                     else
  213.                         SATSoundOff;
  214.                 end;
  215.             fastAnimation: 
  216.                 begin
  217.                     plotFastFlag := not plotFastFlag;
  218.                     CheckItem(fileMenu, fastAnimation, plotFastFlag);
  219.                 end;
  220.             quit: 
  221.                 SkelWhoa;
  222.         end;
  223.     end;
  224.  
  225.     procedure GameWindInit;
  226.     begin
  227. { Tell TransSkel to tell us when to update SATwind. }
  228.         if SkelWindow(gSAT.wind, nil, nil, @GameWindUpdate, nil, nil, nil, nil, false) then
  229.             ;
  230.  
  231.         ShowWindow(gSAT.wind);
  232.         SelectWindow(gSAT.wind);
  233. { Draw the contents of the window (to give the user something to look at during the rest of startup). }
  234.         PeekOffScreen;
  235.     end;
  236.  
  237. { -------------------------------------------------------------------- }
  238. {                        Menu handling procedures                        }
  239. { -------------------------------------------------------------------- }
  240.  
  241. {    Handle selection of "About…" item from Apple menu}
  242.  
  243.     procedure DoAbout;
  244.     begin
  245.         if Alert(aboutAlrt, nil) = 1 then
  246.             ;
  247.     end;
  248.  
  249. {    Initialize menus.  Tell TransSkel to process the Apple menu}
  250. {    automatically, and associate the proper procedures with the}
  251. {    File menu.}
  252.  
  253.     procedure SetUpMenus;
  254.     begin
  255.         SkelApple('About SAT Invaders…', @DoAbout);
  256.         fileMenu := GetMenu(fileMenuRes);
  257.         if SkelMenu(fileMenu, @DoFileMenu, nil, true) then
  258.             ;
  259. { Set the following flags so they match the menu }
  260.         soundFlag := true;
  261.         plotFastFlag := true;
  262.     end;
  263.  
  264. { Hide gamewindow on suspend, so the user can get access to disk icons etc. }
  265.  
  266.     procedure DoSuspendResume (b: boolean);
  267.     begin
  268.         if b then
  269.             begin
  270.                 ShowWindow(gSAT.wind);
  271.                 SelectWindow(gSAT.wind);
  272.             end
  273.         else
  274.             HideWindow(gSAT.wind)
  275.     end;
  276.  
  277.     function DoEvt (e: eventRecord): boolean;
  278.     begin
  279.         if e.what = OSevt then
  280.             begin
  281.                 if BAND(BROTL(e.message, 8), $FF) = SuspendResumeMessage then
  282.                     DoSuspendResume(BAnd(e.message, 1) <> 0);
  283.                 DoEvt := true;
  284.             end
  285.         else
  286.             DoEvt := false;
  287.     end; (* end DoEvent *)
  288.  
  289. { -------------------------------------------------------------------- }
  290. {                                    Main                                }
  291. { -------------------------------------------------------------------- }
  292.  
  293.     var
  294.         gameArea: Rect;
  295.  
  296. begin
  297.     SkelInit(6, nil);                { initialize }
  298.  
  299. { Init all the different parts of the game. }
  300.  
  301.     SetUpMenus;                        { install menu handlers }
  302.  
  303.     SetRect(gameArea, 0, 0, 512, 342);
  304. {We use CustomInitSAT to cover the full screen INCLUDING menu bar area!}
  305.     CustominitSAT(129, 128, gameArea, nil, nil, true, true, true, true, true);
  306. {InitSAT(129, 128, 512, 322);    {PICTs 129 and 128, width 512, height 322.}
  307.     GameWindInit;    { Install the game window (SATwind) in TransSkel and show it. }
  308.     Loadsounds;        { Preload all sound resources }
  309.  
  310. { Call the init routines for all the sprite units (generally to preload faces)!}
  311. { This must be done after InitSAT! }
  312.     InitEnemy;
  313.     InitPlayer;
  314.     InitMissile;
  315.     InitShot;
  316.  
  317.     randSeed := TickCount;    { Set the randseed to something that is random enough. }
  318.  
  319.     SkelEventHook(@DoEvt); { Handle MultiFinder-events }
  320.  
  321.     SkelMain;                    { Loop 'til Quit selected }
  322.     SkelClobber;                { Clean up }
  323.     SATSoundShutUp;            { Terminate sounds, free the sound channel. }
  324. end.